#include "Map.h"
#include <iostream>
#include <fstream>
using namespace std;

Map::Map(): width(20), height(20), mapName("Default")
{
	Allocate();
}

Map::Map(unsigned int newWidth, unsigned int newHeight, const std::string& newMapName): width(newWidth), height(newHeight), mapName(newMapName)
{
	Allocate();	
}

Map::Map(const std::string& fileName)
{
	LoadFromFile(fileName);
}

Map::Map(const Map& rhs)
{
	width = rhs.width;
	height = rhs.height;

	map = new Cell*[width * height];

	CopyCells(map, rhs.map, width, height, rhs.width, rhs.height);
}

Map::~Map()
{
	Deallocate();
}

unsigned int Map::GetWidth() const
{
	return width;
}

unsigned int Map::GetHeight() const
{
	return height;
}

const std::string& Map::GetMapName() const
{
	return mapName;
}

void Map::SetMapName(const std::string& newMapName)
{
	mapName = newMapName;
}

//File IO zal nog uitgebreid moeten worden met dingen zoals richting (laser) naarmate meer types worden
//toegevoegd.
void Map::SaveToFile(const std::string& fileName)
{
	ofstream myfile;
	myfile.open(fileName.c_str(), ios::binary | ios::trunc);

	if (myfile.is_open())
	{

		myfile << mapName << endl;
		myfile << width << endl << height << endl;

		for(int j = 0; j < height; j++)
		{
			for(int i = 0; i < width; i++)
			{
				unsigned int index = i + j * width;

				if(map[index]->GetType().IsRegular())
					myfile << 0 << endl;
				else if(map[index]->GetType().IsWall())
					myfile << 1 << endl;
				else if(map[index]->GetType().IsFlag())
					myfile << 2 << endl;
				else
					//if we meet an unknown type, we write the unknown tag -1
					myfile << -1 << endl;
			}
		}

		myfile.close();
	}
}

void Map::LoadFromFile(const std::string& fileName)
{
	ifstream myfile;
	myfile.open(fileName.c_str(), ios::binary);

	

	if (myfile.is_open())
	{
		unsigned int type;

		

		myfile >> mapName;
		myfile >> width;
		myfile >> height;

		map = new Cell*[width * height];

		for(unsigned int j = 0; j < height; j++)
		{
			for(unsigned int i = 0; i < width; i++)
			{
				myfile >> type;

				switch(type)
				{
				case 1:
					map[i + j * width] = new WallCell;
					break;
				case 2:
					map[i + j * width] = new FlagCell;
					break;
				default:
					map[i + j * width] = new Cell;
					break;
				}
			}
		}
		myfile.close();
	}
}

const Cell& Map::operator()(unsigned int x, unsigned int y) const
{
	return (*map[x + y * width]);
}

void Map::Allocate()
{
	unsigned int length = width * height;

	map = new Cell*[length];

	for(int i = 0; i < length; i++)
		map[i] = new Cell;
}

void Map::Deallocate()
{
	if(!map)
		return;

	unsigned int length = width * height;
	
	for(int i = 0; i < length; i++)
		if(map[i])
			delete map[i];

	delete[] map;

	map = 0;
}

void Map::SetCellType(unsigned int x, unsigned int y, CellType cellType)
{
	unsigned int index = x + y * width;

	if(map[index]->GetType() == cellType)
		return;

	if(map[index])
		delete map[index];

	if(cellType.IsRegular())
		map[index] = new Cell;
	else if(cellType.IsFlag())
		map[index] = new FlagCell;
	else if(cellType.IsWall())
		map[index] = new WallCell;

}

void Map::Print()
{
	for(unsigned int i = 0; i < height; i++)
	{
		for(unsigned int j = 0; j < width; j++)
		{
			unsigned int index = j + i * width;

			if(map[index]->GetType().IsRegular())
				printf("%d", 0);
			else if(map[index]->GetType().IsFlag())
				printf("%d", 2);
			else if(map[index]->GetType().IsWall())
				printf("%d", 1);
		}
		printf("\n");
	}
}

void Map::CopyCells(Cell** dst, Cell** src, unsigned int newWidth, unsigned int newHeight, unsigned int oldWidth, unsigned int oldHeight)
{
	unsigned int copyWidth = min(newWidth, oldWidth);
	unsigned int copyHeight = min(newHeight, oldHeight);

	if(0 == src)
		return;

	for(unsigned int j = 0; j < copyHeight; j++)
	{
		for(unsigned int i = 0; i < copyWidth; i++)
		{
			unsigned int index = i + j * copyWidth;

			dst[index] = src[index]->Clone();
		}
	}
}